"""
The MIT License (MIT)
Copyright © 2022 Walkline Wang (https://walkline.wang)
Gitee: https://gitee.com/walkline/micropython-drivers
"""
__version__ = 'v0.1'

'''
ADC 采样电路

          ADC-→┌─────┐
3V3├─---┌──┐---┘  ┌──┴───┐---┌───┐---─┤│GND
        └──┘      └──────┘   └───┘
         5K        10K可变     5K
'''
from machine import Pin, ADCBlock, Timer

VALID_PINS = {
	32: 4,
	33: 5,
	34: 6,
	35: 7,
	36: 0,
	37: 1,
	38: 2,
	39: 3
}

class PotentiometerException(BaseException):
	pass


class Potentiometer(object):
	def __init__(self, pins=None, rotating_cb=None, timer_id=10, valid_pins=VALID_PINS):
		assert pins is not None, PotentiometerException('pins must be specified')
		assert isinstance(pins, (int, list, tuple)), PotentiometerException('invalid pin format')
		assert rotating_cb is not None, PotentiometerException('rotating_cb must be specified')
		assert isinstance(valid_pins, (int, dict)), PotentiometerException('invalid valid_pins format')

		self.__pin_list = []
		self.__adc_list = []
		self.__last_sampling_list = []
		self.__rotating_cb = rotating_cb
		self.__adcblock = ADCBlock(1, bits=12)

		if isinstance(pins, (list, tuple)):
			for _ in pins:
				if self.is_validate_pin(_):
					self.__adc_list.append(self.__adcblock.connect(VALID_PINS[_], Pin(_)))
					self.__adc_list[-1].atten(3)
					self.__pin_list.append(_)
					self.__last_sampling_list.append(0)
		else:
			if self.is_validate_pin(pins):
				self.__adc_list.append(self.__adcblock.connect(VALID_PINS[pins], Pin(pins)))
				self.__adc_list[-1].atten(3)
				self.__pin_list.append(pins)
				self.__last_sampling_list.append(0)

		if timer_id is not None:
			self.__timer = Timer(timer_id)

			self.__timer.init(
				mode=Timer.PERIODIC,
				period=20,
				callback=self.timer_callback
			)

	def deinit(self):
		for _ in self.__adc_list:
			_ = None

		if self.__timer is not None:
			self.__timer.deinit()
			self.__timer = None

	def timer_callback(self, timer=None):
		if len(self.__adc_list) == 0:
			return

		sample_avg = 0

		for index in range(len(self.__adc_list)):
			for _ in range(20):
				sample_avg += self.__adc_list[index].read()

			sample_avg = int(sample_avg / 20)

			if self.__last_sampling_list[index] != sample_avg and abs(self.__last_sampling_list[index] - sample_avg) > 9:
				if self.__rotating_cb:
					self.__rotating_cb(self.__pin_list[index], self.__last_sampling_list[index] < sample_avg, sample_avg)

				self.__last_sampling_list[index] = sample_avg

	@staticmethod
	def is_validate_pin(pin):
		if pin in VALID_PINS.keys():
			return True
		else:
			print(f'invalid pin ({pin}), ignored')
			return False


def run_test():
	adc_pin = 32
	max_value = 800	# adc 读数最大值
	scales = 5		# 旋转刻度数量
	scale_range = int(max_value / scales) # 每刻度读数范围
	last_scale = 0

	def adc_rotating_cb(pin, direction, sampling):
		nonlocal last_scale

		if False:
			# 使用 sampling 确定 max_value，并向上取整
			print(f'potentiometer {pin} rotating {"forward" if direction else "backward"}: {sampling}')
		else:
			scale_now = int(sampling / scale_range)

			if last_scale != scale_now:
				print(f'potentiometer {pin} scale: {scale_now}')
				last_scale = scale_now

	if isinstance(adc_pin, (list, tuple)):
		for pin in adc_pin:
			print(f'adc_pin {pin} validation: {Potentiometer.is_validate_pin(pin)}')
	else:
		print(f'adc_pin {adc_pin} validation: {Potentiometer.is_validate_pin(adc_pin)}')

	# ADC1 可用引脚及通道
	VALID_PINS = {
		32: 4,
		33: 5,
		34: 6,
		35: 7,
		36: 0,
		37: 1,
		38: 2,
		39: 3
	}

	potentiometer = Potentiometer(
		pins=adc_pin,
		rotating_cb=adc_rotating_cb,
		# valid_pins=VALID_PINS # 可以使用驱动自带设置，或手动指定
	)


if __name__ == "__main__":
	try:
		run_test()
	except KeyboardInterrupt:
		pass
